package com.ruoyi.file.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.file.domain.SysStorageConfig;
import com.ruoyi.file.mapper.SysStorageConfigMapper;
import com.ruoyi.file.service.ISysStorageConfigService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.S3ClientBuilder;
import software.amazon.awssdk.services.s3.model.HeadBucketRequest;

import java.net.URI;
import java.util.Arrays;
import java.util.List;
import com.ruoyi.file.enums.StorageTypeEnum;

/**
 * 存储配置Service业务层处理
 *
 * @author ruoyi
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class SysStorageConfigServiceImpl extends ServiceImpl<SysStorageConfigMapper, SysStorageConfig> implements ISysStorageConfigService {

    private final SysStorageConfigMapper storageConfigMapper;

    /**
     * 查询存储配置列表
     *
     * @param sysStorageConfig 存储配置
     * @return 存储配置
     */
    @Override
    public List<SysStorageConfig> selectStorageConfigList(SysStorageConfig sysStorageConfig) {
        LambdaQueryWrapper<SysStorageConfig> lqw = new LambdaQueryWrapper<>();
        lqw.like(StringUtils.isNotBlank(sysStorageConfig.getConfigName()), SysStorageConfig::getConfigName, sysStorageConfig.getConfigName());
        lqw.eq(StringUtils.isNotBlank(sysStorageConfig.getStorageType()), SysStorageConfig::getStorageType, sysStorageConfig.getStorageType());
        lqw.eq(sysStorageConfig.getStatus() != null, SysStorageConfig::getStatus, sysStorageConfig.getStatus());
        lqw.eq(sysStorageConfig.getIsDefault() != null, SysStorageConfig::getIsDefault, sysStorageConfig.getIsDefault());
        lqw.eq(SysStorageConfig::getDelFlag, 0);
        lqw.orderByAsc(SysStorageConfig::getSortOrder);
        return this.list(lqw);
    }

    /**
     * 新增存储配置
     *
     * @param sysStorageConfig 存储配置
     * @return 结果
     */
    @Override
    @CacheEvict(value = "storageConfig", allEntries = true)
    public int insertStorageConfig(SysStorageConfig sysStorageConfig) {
        // 如果设置为默认，先将其他配置设为非默认
        if (sysStorageConfig.getIsDefault() != null && sysStorageConfig.getIsDefault() == 1) {
            storageConfigMapper.resetAllDefault();
        }
        return storageConfigMapper.insert(sysStorageConfig);
    }

    /**
     * 修改存储配置
     *
     * @param sysStorageConfig 存储配置
     * @return 结果
     */
    @Override
    @CacheEvict(value = "storageConfig", allEntries = true)
    public int updateStorageConfig(SysStorageConfig sysStorageConfig) {
        // 如果设置为默认，先将其他配置设为非默认
        if (sysStorageConfig.getIsDefault() != null && sysStorageConfig.getIsDefault() == 1) {
            storageConfigMapper.resetAllDefault();
        }
        return storageConfigMapper.updateById(sysStorageConfig);
    }

    /**
     * 批量删除存储配置
     *
     * @param configIds 需要删除的存储配置主键
     * @return 结果
     */
    @Override
    @CacheEvict(value = "storageConfig", allEntries = true)
    public int deleteStorageConfigByIds(Long[] configIds) {
        return storageConfigMapper.deleteByIds(Arrays.asList(configIds));
    }

    /**
     * 删除存储配置信息
     *
     * @param configId 存储配置主键
     * @return 结果
     */
    @Override
    @CacheEvict(value = "storageConfig", allEntries = true)
    public int deleteStorageConfigById(Long configId) {
        return storageConfigMapper.deleteById(configId);
    }

    /**
     * 获取默认存储配置
     *
     * @return 默认存储配置
     */
    @Override
    @Cacheable(value = "storageConfig", key = "'default'")
    public SysStorageConfig getDefaultConfig() {
        return storageConfigMapper.selectDefaultConfig();
    }

    /**
     * 设置默认存储配置
     *
     * @param configId 配置ID
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(value = "storageConfig", allEntries = true)
    public boolean setDefaultConfig(Long configId) {
        // 先重置所有配置为非默认
        storageConfigMapper.resetAllDefault();
        // 设置指定配置为默认
        return storageConfigMapper.setDefault(configId) > 0;
    }

    /**
     * 测试存储配置连接
     *
     * @param sysStorageConfig 存储配置
     * @return 测试结果
     */
    @Override
    public boolean testConnection(SysStorageConfig sysStorageConfig) {
        try {
            // 使用S3客户端测试连接
            S3Client s3Client = createS3Client(sysStorageConfig);

            // 尝试访问存储桶
            HeadBucketRequest headBucketRequest = HeadBucketRequest.builder().bucket(sysStorageConfig.getBucketName()).build();

            s3Client.headBucket(headBucketRequest);
            s3Client.close();

            return true;
        } catch (Exception e) {
            log.error("测试存储配置连接失败: {}", e.getMessage());
            return false;
        }
    }

    /**
     * 根据ID获取存储配置（缓存）
     *
     * @param configId 配置ID
     * @return 存储配置
     */
    @Override
    @Cacheable(value = "storageConfig", key = "#configId")
    public SysStorageConfig getConfigById(Long configId) {
        return this.getById(configId);
    }

    /**
     * 创建S3客户端
     *
     * @param config 存储配置
     * @return S3客户端
     */
    private S3Client createS3Client(SysStorageConfig config) {
        AwsBasicCredentials awsCredentials = AwsBasicCredentials.create(config.getAccessKey(), config.getSecretKey());

        S3ClientBuilder builder = S3Client.builder().credentialsProvider(StaticCredentialsProvider.create(awsCredentials)).endpointOverride(URI.create(config.getEndpoint())).region(Region.of(config.getRegion()));

        // 根据存储类型设置不同的访问风格
        try {
            StorageTypeEnum storageType = StorageTypeEnum.getByCode(config.getStorageType());
            switch (storageType) {
                case MINIO, AWS -> builder.forcePathStyle(true); // MinIO和AWS S3使用路径风格
                case ALIYUN, TENCENT -> builder.forcePathStyle(false); // 阿里云OSS、腾讯云COS使用虚拟主机风格
            }
        } catch (IllegalArgumentException e) {
            builder.forcePathStyle(false); // 默认使用虚拟主机风格
        }

        return builder.build();
    }
}
